package io.noties.markwon.plugin.typogram.parser

import com.gitee.wsl.common.svg.container.Container
import com.gitee.wsl.common.svg.elements.Element
import com.gitee.wsl.common.svg.container.G
import com.gitee.wsl.common.svg.SVG
import com.gitee.wsl.common.ui.base.UT
import com.gitee.wsl.ext.base.isBaseChar
import com.gitee.wsl.ext.base.v

class QuickParser(var zoom:Float = 1f,var  padding:Float = 0f,var isDebug:Boolean=false) {

    var defaultTextSize:Float? = null


    protected fun grid(width:Int, height:Int,svg: Container) {
        svg.group {
            line {
                x1 = 15f
                y1 = 0f
                x2 = 15f
                y2 = 54f
                cssClass = "center"
            }

            line {
                x1 = 0f
                y1 = 30f
                x2 = 30f
                y2 = 54f
                cssClass = "center"
            }

            for ( i in 0 .. width * 30 step 3) {
                line {
                    x1 = i.toFloat()
                    y1 = 0f
                    x2 = i.toFloat()
                    y2 = 54f * height
                    cssClass = "grid"
                }
           }

            for ( i in 0 .. height * 54 step 3) {
                line {
                    x1 = 0f
                    y1 = i.toFloat()
                    x2 = 30f*width
                    y2 = i.toFloat()
                    cssClass = "grid"
                }
            }
        }
    }

    protected fun cross(top:Boolean = false, right:Boolean = false, bottom:Boolean = false, left:Boolean = false, topRight:Boolean = false, bottomRight:Boolean = false, bottomLeft:Boolean = false, topLeft:Boolean = false,svg: Container): G {
        return svg.group{
            if (top) {
                line {
                    x1 = 15f
                    y1 = 0f
                    x2 = 15f
                    y2 = 27f
                    cssClass = "part"
                }
            }
            if (right) {
                line {
                    x1 = 15f
                    y1 = 27f
                    x2 = 30f
                    y2 = 27f
                    cssClass = "part"
                }
            }

            if (bottom) {
                line {
                    x1 = 15f
                    y1 = 27f
                    x2 = 15f
                    y2 = 54f
                    cssClass = "part"
                }
            }

            if (left) {
                line {
                    x1 = 0f
                    y1 = 27f
                    x2 = 15f
                    y2 = 27f
                    cssClass = "part"
                }
            }

            /*polygon {
                points(0f to 0f,20.6f to 0f,20.6f to 3f,0f to 3f)
            }*/

            if (topRight) {
                // line.setAttribute("transform", "scale(1, 1)");
                // line.setAttribute("clip-path", "polygon(-6 -6, 15 -6, 15 30, -6 30)");
                // line.setAttribute("stroke-linecap", "square !important");

                //const mask = document.createElementNS(
                //  "http://www.w3.org/2000/svg", "polygon");
                //mask.setAttribute("points", "0 0, 15 0, 15 18, 0 18");
                //result.appendChild(mask);
                //console.log("hi");
                line {
                    x1 = 30f
                    y1 = 0f
                    x2 = 15f
                    y2 = 27f
                    cssClass = "part"
                }
            }

            if (bottomRight) {
                line {
                    x1 = 15f
                    y1 = 27f
                    x2 = 30f
                    y2 = 54f
                    cssClass = "part"
                }
            }

            if (bottomLeft) {
                line {
                    x1 = 15f
                    y1 = 27f
                    x2 = 0f
                    y2 = 54f
                    cssClass = "part"
                }
            }

            if (topLeft) {
                line {
                    x1 = 0f
                    y1 = 0f
                    x2 = 15f
                    y2 = 27f
                    cssClass = "part"
                }
            }
        }
    }

    protected fun glyphs(current:Char,cell: CellAround,svg: Container): Element {
        return glyphs(current,cell.top, cell.right, cell.bottom, cell.left, cell.topRight, cell.bottomRight, cell.bottomLeft, cell.topLeft,svg)
    }

    protected fun glyphs(current:Char,top:Char = ' ' , right:Char = ' ', bottom:Char = ' ', left:Char = ' ', topRight:Char = ' ', bottomRight:Char = ' ', bottomLeft:Char = ' ', topLeft:Char = ' ',svg: Container): Element {
        return when(current){
            '|'->{
                svg.group{
                    if (right == '_') {
                        line {
                            x1 = 10f
                            y1 = 51f
                            x2 = 30f
                            y2 = 51f
                            cssClass = "part"
                        }
                    }
                    if (left == '_') {
                        line {
                            x1 = 0f
                            y1 = 51f
                            x2 = 12f
                            y2 = 51f
                            cssClass = "part"
                        }
                    }
                    if (topRight == '_') {
                        line {
                            x1 = 12f
                            y1 = -3f
                            x2 = 30f
                            y2 = -3f
                            cssClass = "part"
                        }
                    }
                    if (topLeft == '_') {
                        line {
                            x1 = 0f
                            y1 = -3f
                            x2 = 18f
                            y2 = -3f
                            cssClass = "part"
                        }
                    }
                    // const leg =  && ;
                    // const head =  && ;
                    //console.log(!(bottomLeft == "/" && bottomRight == "\\"));
                    //console.log(!(topRight == "/" && topLeft == "\\"));
                    cross(
                        !(topRight == '/' && topLeft == '\\'), // top
                        '-' == right, // right
                        !(bottomLeft == '/' && bottomRight == '\\'), // bottom
                        '-' == left, // left
                        topRight == '/', // topRight
                        bottomRight == '\\', // bottomRight
                        bottomLeft == '/', // bottomLeft
                        topLeft == '\\',  // topLeft
                            svg=this,
                    )
                }
            }
            '─','-'->{
                cross(
                    '|' == top, // top
                    true, // right
                    '|' == bottom, // bottom
                    true, // left
                    false, // topRight
                    false, // bottomRight
                    false, // bottomLeft
                    false  ,  // topLeft
                    svg,
                )
            }
           '~'->{
               svg.line {
                   x1 = 9f
                   y1 = 27f
                   x2 = 24f
                   y2 = 27f
                   cssClass = "part"
               }
            }
            '_'->{
               val line = glyphs('-',top, right, bottom, left, topRight, bottomRight, bottomLeft, topLeft,svg)
                line.attributes["transform"] = "translate(0 24)"
                line
            }
           ':'->{
               svg.group {
                   line {
                       x1 = 15f
                       y1 = 0f
                       x2 = 15f
                       y2 = 60f
                       cssClass = "part"
                       attributes["style"]="stroke-dasharray: 15; stroke-dashoffset: 0;"
                   }
                   if (top == '+') {
                       line {
                           x1 = 15f
                           y1 = -24f
                           x2 = 15f
                           y2 = -15f
                           cssClass = "part"
                       }
                   }
                   if (bottom == '+') {
                       line {
                           x1 = 15f
                           y1 = 60f
                           x2 = 15f
                           y2 = 78f
                           cssClass = "part"
                       }
                   }
               }
           }
           '='->{
               svg.group {
                   line {
                       x1 = 0f
                       y1 = 21f
                       x2 = 30f
                       y2 = 21f
                       cssClass = "part"
                   }

                   line {
                       x1 = 0f
                       y1 = 30f
                       x2 = 30f
                       y2 = 30f
                       cssClass = "part"
                   }
               }
           }
          '*'->{
                svg.group {
                    circle {
                        cx = 0f
                        cy = 0f
                        r = 21f
                        strokeColor = "none"
                        attributes["transform"]="translate(15, 27)"
                    }
                    cross(
                        v('+', '|').contains(top),
                        v('+', '-').contains(right),
                        v('+', '|').contains(bottom),
                        v('+', '-').contains(left),
                        v('/').contains(topRight),
                        v('\\').contains(bottomRight),
                        v('/').contains(bottomLeft),
                        v('\\').contains(topLeft),  // topLeft
                        svg=this,
                    )
                }
            }
            'o'->{
                svg.group {
                    circle {
                        cx = 0f
                        cy = 0f
                        r = 18f
                        strokeWidth = 6.UT
                        fill = "none"
                        strokeColor = "black"
                        attributes["transform"] = "translate(15, 27)"
                    }

                    cross(
                        v('+', '|').contains(top),
                        v('+', '-').contains(right),
                        v('+', '|').contains(bottom),
                        v('+', '-').contains(left),
                        v('/').contains(topRight),
                        v('\\').contains(bottomRight),
                        v('/').contains(bottomLeft),
                        v('\\').contains(topLeft),  // topLeft
                        svg=this,
                    )

                    circle {
                        cx = 0f
                        cy = 0f
                        r = 15f
                        strokeWidth = 6.UT
                        fill = "white"
                        attributes["opacity"] = "100%"
                        attributes["transform"] = "translate(15, 27)"
                    }
                }
            }
            '/' -> {
               svg.group {
                   cross(
                       '|' == top, // top
                       false, // right
                       '|' == bottom, // bottom
                       false, // left
                       true, // topRight
                       false, // bottomRight
                       true,  // bottomLeft
                       false  ,  // topLeft
                       svg=this,
                   )
                   if (right == '\\') {
                       val tip = cross(
                           false,
                           false,
                           false,
                           false,
                           false,
                           false,
                           true, // bottomLeft
                           false,  // topLeft
                           svg=this,
                       )
                       tip.attributes["transform"] = "translate(30 -54)"
                       tip.attributes["clip-path"] = "polygon(-3 0, 0 0, 0 54, -3 54)"
                   }
                   if (left == '\\') {
                       val tip = cross(
                           false,
                           false,
                           false,
                           false,
                           true, // topRight
                           false,
                           false, // bottomLeft
                           false,  // topLeft
                           svg=this,
                       )
                       tip.attributes["transform"] = "translate(-30 54)"
                       tip.attributes["clip-path"] = "polygon(15 -6, 33 -6, 33 6, 15 6)"
                   }

                   if (right == '_') {
                       glyphs('_',top, right, bottom, left, topRight, bottomRight, bottomLeft, topLeft,this)
                   }
               }
            }
            '\\'->{
                svg.group {
                    cross(
                        '|' == top, // top
                        false, // right
                        '|' == bottom, // bottom
                        false, // left
                        false, // topRight
                        true, // bottomRight
                        false, // bottomLeft
                        true  ,  // topLeft
                           svg=this,
                    )
                    if (left == '/') {
                        val tip = cross(
                            false,
                            false,
                            false,
                            false,
                            false,
                            true, // bottomRight
                            false,
                            false,  // topLeft
                            svg,
                        )
                        tip.attributes["transform"] = "translate(-30 -54)"
                        tip.attributes["clip-path"] = "polygon(15 0, 30 0, 30 54, 15 54)"
                    }
                    if (right == '/') {
                        val tip = cross(
                            false,
                            false,
                            false,
                            false,
                            false,
                            false,
                            false,
                            true,  // topLeft
                            svg,
                        )

                        tip.attributes["transform"] = "translate(30 54)"
                        tip.attributes["clip-path"] = "polygon(-3 0, 0 0, 0 6, -3 6)"
                    }

                    if (left == '_') {
                       glyphs('_',top, right, bottom, left, topRight, bottomRight, bottomLeft, topLeft,this)
                    }
                }
            }
            '#'->{
                svg.group {
                    polygon {
                        points(0f to  0f,42f to 0f,42f to 42f,0f to 42f)
                        attributes["transform"]="translate(-6, 6)"
                    }

                   cross(
                        v('+', '|').contains(top),
                        v('+', '-').contains(right),
                        v('+', '|').contains(bottom),
                        v('+', '-').contains(left),
                        v('/').contains(topRight),
                        v('\\').contains(bottomRight),
                        v('/').contains(bottomLeft),
                        v('\\').contains(topLeft),  // topLeft
                       svg=this,
                    )
                }
            }
            '┐','┌','+','└','┘'->{
                svg.group {
                    val r  = v('*',  '#', '-', '+', '~', '>', '.', '\'', '`').contains(right);
                    val l  = v('*',  '#', '-', '+', '~', '<', '.', '\'', '`').contains(left);
                    val t  = v('*',  '#', '|', '+', '.', '`', '^').contains(top);
                    val b  = v('*',  '#', '|', '+', '\'', '`', 'v').contains(bottom);
                    val tR = v('/',  '*', '#').contains(topRight);
                    val bR = v('\\', '*', '#').contains(bottomRight);
                    val tL = v('\\', '*', '#').contains(topLeft);
                    val bL = v('/',  '*', '#').contains(bottomLeft);

                    // cross
                    cross(
                        t,
                        r,
                        b,
                        l,
                        tR,
                        bR,
                        bL,
                        tL,  // topLeft
                        svg=this,
                    )

                    // center
                    if ((l || r) && (b || t)) {
                        polygon {
                            points = "0,0 6,0 6,6 0,6"
                            attributes["transform"] = "translate(-3 -3) translate(15 27)"
                        }
                    }

                    // tip
                    if (tR || tL) {
                        val center = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            tL, // bottomRight
                            tR, // bottomLeft
                            false,  // topLeft
                            svg=this,
                        )
                        center.attributes["clip-path"]="polygon(0 -3, 30 -3, 30 0, 0 0)"
                    }

                    if (bR || bL) {
                        val center = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            bL, // topRight
                            false, // bottomRight
                            false, // bottomLeft
                            bR,  // topLeft
                            svg=this,
                        )
                        center.attributes["clip-path"]= "polygon(0 27, 15 27, 15 30, 0 30)"
                    }

                    if (bL || tL) {
                        val center = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            bL && bR, // topRight
                            tL && tR, // bottomRight
                            false, // bottomLeft
                            false,  // topLeft
                            svg=this,
                        )
                        center.attributes["clip-path"]=  "polygon(-3 0, 0 0, 0 54, -3 54)"

                    }

                    if (bR || tR) {
                        val center = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            false, // bottomRight
                            tR && tL, // bottomLeft
                            bR && bL ,  // topLeft
                            svg=this,
                        )
                        //console.log(center);
                        center.attributes["clip-path"] = "polygon(15 0, 30 0, 30 54, 15 54)"

                    }

                    if (r || l) {
                        val center = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            r || bL, // topRight
                            tL, // bottomRight
                            tR, // bottomLeft
                            l || bR,  // topLeft
                            svg=this,
                        )
                        center.attributes["clip-path"] = "polygon(-3 24, 30 24, 30 30, -3 30)"
                    }
                }
            }
            '.','\'','`'->{
                svg.group {
                    // top-right
                    if ((right == '-' || right == '+') && (bottom == '|' || bottom == '\'' || bottom == '`' || bottom == '+')) {
                        pathDef {
                            d = """
                            M 30 24
                            A 18 18, 0, 0, 0, 12 42
                            L 12 54
                            L 18 54
                            L 18 42
                            A 12 12, 0, 0, 1, 30 30
                            Z"""
                        }
                    }

                    // top-left
                    if ((left == '-' || left == '+') && (bottom == '|' || bottom == '\'' || bottom == '`' || bottom == '+')) {
                        pathDef {
                            d = """
                        M 0 24
                        A 18 18, 0, 0, 1, 18 42
                        L 18 54
                        L 12 54
                        L 12 42
                        A 12 12, 0, 0, 0, 0 30
                        Z"""}
                    }

                    // top-right
                    if ((right == '-' || right == '+') && (top == '|' || top == '.' || top == '+')) {
                        pathDef {
                            d = """
                            M 30 30
                        A 18 18, 0, 0, 1, 12 12
                        L 12 0
                        L 18 0
                        L 18 12
                        A 12 12, 0, 0, 0, 30 24
                        Z"""
                        }
                    }

                    // bottom-left
                    if ((left == '-' || left == '+') && (top == '|' || top == '.' || top == '+')) {
                        pathDef {
                            d = """
                           M 0 30
                        A 18 18, 0, 0, 0, 18 12
                        L 18 0
                        L 12 0
                        L 12 12
                        A 12 12, 0, 0, 1, 0 24
                        Z"""
                        }
                    }

                    // bottom right-topRight
                    if (right == '-' && topRight == '/') {
                        pathDef {
                            d = """
                          M 30 30
                        A 12 12, 0, 0, 1, 18 18
                        L 18 15
                        L 24 15
                        L 24 18
                        A 6 6, 0, 0, 0, 30 24
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            true, // topRight
                            false, // bottomRight
                            false, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]="polygon(15px -10px, 30px -10px, 30px 30px, 2px 15px)"
                    }

                    // right-topLeft
                    if (right == '-' && topLeft == '\\') {
                        pathDef {
                            d = """
                          M -3 0
                        A 60 60, 0, 0, 0, 30 30
                        L 30 24
                        A 60 60, 0, 0, 1, 0 -6
                        Z"""
                        }
                    }

                    // left-topRight
                    if (left == '-' && topRight == '/') {
                        pathDef {
                            d = """
                         M 0 30
                        A 60 60, 0, 0, 0, 33 0
                        L 30 -6
                        A 60 60, 0, 0, 1, 0 24
                        Z"""
                        }
                    }

                    // bottom left-topLeft
                    if (left == '-' && topLeft == '\\') {

                        pathDef {
                            d = """
                         M 0 30
                        A 12 12, 0, 0, 0, 12 18
                        L 12 15
                        L 6 15
                        L 6 18
                        A 6 6, 0, 0, 1, 0 24
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            false, // bottomRight
                            false, // bottomLeft
                            true ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"] = "polygon(-3 -3, 12 -3, 12 18, -3 18)"
                    }

                    // bottom-topRight
                    if (bottom == '|' && topRight == '/') {
                        pathDef {
                            d = """
                        M 12 54
                        A 120 120, 0, 0, 1, 30 -6
                        L 37 -6
                        A 120 120, 0, 0, 0, 18 54
                        Z"""
                        }
                    }

                    // top-bottomRight
                    if (top == '|' && bottomRight == '\\') {
                        pathDef {
                            d = """
                       M 30 60
                        A 120 120, 0, 0, 1, 12 0
                        L 18 0
                        A 120 120, 0, 0, 0, 37 60
                        Z"""
                        }
                    }

                    // top-bottomLeft
                    if (top == '|' && bottomLeft == '/') {

                        pathDef {
                            d = """
                        M 0 60
                        A 120 120, 0, 0, 0, 18 0
                        L 12 0
                        A 120 120, 0, 0, 1, -7 60
                        Z"""
                        }
                    }

                    // bottom-topLeft
                    if (bottom == '|' && topLeft == '\\') {
                        pathDef {
                            d = """
                       M 12 54
                        A 120 120, 0, 0, 0, -7 -6
                        L 0 -6
                        A 120 120, 0, 0, 1, 18 54
                        Z"""
                        }
                    }

                    // right-bottomLeft
                    if (right == '-' && bottomLeft == '/') {
                        pathDef {
                            d = """
                       M 0 48
                        A 42 42, 0, 0, 1, 30 24
                        L 30 30
                        A 42 42, 0, 0, 0, 6 48
                        Z"""
                        }


                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            false, // bottomRight
                            true, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]= "polygon(-3 15, 12 15, 12 30, -3 30)"
                    }

                    // left-bottomRight
                    if (left == '-' && bottomRight == '\\') {
                        pathDef {
                            d = """
                       M 0 24
                        A 42 42, 0, 0, 1, 30 48
                        L 24 48
                        A 42 42, 0, 0, 0, 0 30
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            true, // bottomRight
                            false, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]= "polygon(-3 15, 12 15, 21 30, -3 30)"
                    }

                    // left-bottomLeft
                    if (left == '-' && bottomLeft == '/') {

                        pathDef {
                            d = """
                       M 0 24
                        A 12 12, 0, 0, 1, 12 39
                        L 6 39
                        A 6 6, 0, 0, 0, 0 30
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            false, // bottomRight
                            true, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]= "polygon(-3 6, 12 6, 12 30, -3 30)"
                    }

                    // right-bottomRight
                    if (right == '-' && bottomRight == '\\') {

                        pathDef {
                            d = """
                       M 30 24
                        A 12 12, 0, 0, 0, 18 39
                        L 24 39
                        A 6 6, 0, 0, 1, 30 30
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            true, // bottomRight
                            false, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]= "polygon(3 6, 18 6, 18 30, 3 30)"
                    }

                    // bottomLeft-bottomRight
                    if (bottomLeft == '/' && bottomRight == '\\') {
                        pathDef {
                            d = """
                       M 3 42
                        A 15 15, 0, 0, 1, 27 42
                        L 25 51
                        A 9 9, 0, 0, 0, 5 51
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            true, // bottomRight
                            true, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]= "polygon(-3 15, 33 15, 33 30, -3 30)"

                    }

                    // topLeft-topRight
                    if (topLeft == '\\' && topRight == '/') {

                        pathDef {
                            d = """
                       M 3 12
                        A 15 15, 0, 0, 0, 27 12
                        L 22 9
                        A 9 9, 0, 0, 1, 8 9
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            true, // topRight
                            false, // bottomRight
                            false, // bottomLeft
                            true  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"]= "polygon(-3 -3, 33 -3, 33 12, -3 12)"

                    }

                    // topRight-bottomRight
                    if (topRight == '/' && bottomRight == '\\') {
                        pathDef {
                            d = """
                        M 22 9
                        A 30 30, 0, 0, 0, 22 45
                        L 28 45
                        A 30 30, 0, 0, 1, 28 9
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            true, // topRight
                            true, // bottomRight
                            false, // bottomLeft
                            false  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"] = "polygon(6 -3, 33 -3, 33 57, 6 57)"

                    }

                    // topLeft-bottomLeft
                    if (topLeft == '\\' && bottomLeft == '/') {

                        pathDef {
                            d = """
                        M 8 9
                        A 30 30, 0, 0, 1, 8 45
                        L 2 45
                        A 30 30, 0, 0, 0, 2 9
                        Z"""
                        }

                        val line = cross(
                            false, // top
                            false, // right
                            false, // bottom
                            false, // left
                            false, // topRight
                            false, // bottomRight
                            true, // bottomLeft
                            true  ,  // topLeft
                            svg=this,
                        )
                        line.attributes["clip-path"] = "polygon(-3 -3, 9 -3, 9 57, -3 57)"
                    }
                }
            }
            '>','►'->{
                svg.group {
                    polygon {
                        points = "0,0 42,18 0,36"
                        var reach = 0
                        if (right == '*' || right == 'o' || right == '#') {
                            reach -= 18
                        }
                        attributes["transform"] = "translate(${reach} 9)"
                    }
                   /* const center = document.createElementNS(
                            "http://www.w3.org/2000/svg", "polygon");
                    center.setAttribute("points", "-3,0 6,0 6,6 -3,6");
                    center.setAttribute("transform", "translate(15 24)");
                    result.appendChild(center);
                    result.appendChild(cross([
                        false, // top
                        false, // right
                        false, // bottom
                        ["-", "+"].includes(left), // left
                        false, // topRight
                        false, // bottomRight
                        ["/"].includes(bottomLeft), // bottomLeft
                        ["\\"].includes(topLeft) // topLeft
                    ]));*/
                }
            }
            '<'-> {
                svg.group {
                    polygon {
                        points = "0,0 42,18 0,36"
                        var reach = 30
                        if (left == '*' || left == 'o' || left == '#') {
                            reach += 18
                        }
                        attributes["transform"] =
                            "translate(${reach} 9) translate(0 36) rotate(180)"
                    }
                    /*//const center = document.createElementNS(
                    //  "http://www.w3.org/2000/svg", "polygon");
                    //center.setAttribute("points", "0,0 9,0 9,6 0,6");
                    //center.setAttribute("transform", "translate(9 24)");
                    //result.appendChild(center);
                    result.appendChild(cross([
                        false, // top
                        ["-", "+"].includes(right), // right
                        false, // bottom
                        false, // left
                        ["/"].includes(topRight), // topRight
                        ["\\"].includes(bottomRight), // bottomRight
                        false, // bottomLeft
                        false // topLeft
                    ]));
                    return result;*/

                }
            }
            'v','V'->{
                svg.group {
                    polygon {
                        points = "0,0 42,18 0,36"
                        var reach = 36
                        if (bottom == ' ') {
                            reach = 12;
                        } else if (bottom == '_') {
                            reach += 18;
                        } else if (bottom == '*' || bottom == 'o' ||  bottom == '#') {
                            reach -= 18;
                        }
                        if (topRight == '/') {
                            attributes["transform"] = "translate(-36 33) rotate(${90 + 22.5}, 42, 18)"
                        } else if (topLeft == '\\') {
                            attributes["transform"] = "translate(-18 33) rotate(${90 - 22.5}, 42, 18)"
                        } else {
                            attributes["transform"] = "translate(33 ${reach}) rotate(90)"
                        }
                    }

                   cross(
                        v('|', '+').contains(top), // top
                        false, // right
                        v('|', '+').contains(top), // bottom
                        false, // left
                        v('/').contains(topRight), // topRight
                        false, // bottomRight
                        false, // bottomLeft
                        v('\\').contains(topLeft) ,  // topLeft
                       svg=this,
                    )
                }
            }
            '^'->{
                svg.group {
                    polygon {
                        points = "0,0 42,18 0,36"

                        var reach = 42
                        if (top == '-') {
                            reach -= 15
                        }
                        if (bottomLeft == '/') {
                            attributes["transform"] = "translate(-18 -15) rotate(${- 45 - 22.5}, 42, 18)"
                        } else if (bottomRight == '\\') {
                            attributes["transform"] = "translate(-36 -15) rotate(${- 90 - 22.5}, 42, 18)"
                        } else {
                            attributes["transform"] = "translate(-3 ${reach}) rotate(-90)"
                        }
                    }

                   cross(
                        false, // top
                        false, // right
                        v('+', '|').contains(bottom), // bottom
                        false, // left
                        false, // topRight
                        '\\'== bottomRight, // bottomRight
                        '/'== bottomLeft, // bottomLeft
                        false ,  // topLeft
                       svg=this,
                    )
                }
            }
            else -> {
                svg.text {  }
            }
        }
    }

    protected fun text(char:String, reserved:Boolean=false,svg: Container) {
            svg.text {
                body = char
                if(reserved)
                   cssClass = "reserved"
                defaultTextSize?.let {
                    fontSize = it.toString()
                }
                attributes["transform"] = "translate(15 24)"
            }
    }

    var word = mutableListOf<Char>()
    var wordStartX = -1
    var lastStartX = -1
    var wordStartY = -1


    protected fun initWord(){
        word = mutableListOf<Char>()
        wordStartX = -1
        lastStartX = -1
        wordStartY = -1
    }

    protected fun isNewWord(x:Int,y:Int):Boolean{
        return lastStartX == -1 || (lastStartX != x-1 )
    }

    protected fun addText(char:Char,x:Int,y:Int,isLineEnd:Boolean, reserved:Boolean=false,svg: Container){
        if(isNewWord(x,y) || isLineEnd) {
            if (word.isNotEmpty()){
                svg.group {
                    text(word.joinToString(""), reserved, this)
                    attributes["transform"] = "translate(${wordStartX * 30} ${wordStartY * 54})"
                }
            }
            initWord()
            wordStartX = x
            wordStartY = y
        }
        lastStartX = x
        word.add(char)
    }

    protected fun parser(diagram:List<String>, container: Container) {
        var isStr = false
        var isReserved = false

        diagram.forEachIndexed { y, line ->
                    line.forEachIndexed line@{ x, char ->

                        if (char == ' ' || char == '"') {
                            if (char == ' ' && !isNewWord(x, y))
                                addText(char, x, y, isReserved, x == line.length - 1, container)
                            return@line
                        }

                        isReserved = glyphsCharList.contains(char)

                        isStr = false

                        for (i in 0 until x) {
                            if (line[i] == '"')
                                isStr = !isStr
                        }

                        val cellAround = around(diagram, x, y)

                        if (char.isBaseChar()) {
                            // We special case "v", which is a down arrow, and also a text character.
                            //str = str || (left.match(/[A-Za-uw-z0-9]/) || right.match(/[A-Za-uw-z0-9]/));
                            isStr =
                                isStr || (cellAround.left.isBaseChar('v')) || cellAround.right.isBaseChar(
                                    'v'
                                )
                        }

                        isReserved = isReserved && !isStr

                        if (isReserved) {
                            container.group {
                                attributes["transform"] = "translate(${x * 30} ${y * 54})"
                                glyphs(char, cellAround, this)
                            }
                        } else {
                            //text(char.toString(), isReserved, this)
                            addText(char, x, y, false, x == line.length - 1, container)
                        }
                    }
            }
    }

    var width:Float=0f
    var height:Float=0f

    fun renderWithSize(source:String):Pair<String,Pair<Float,Float>>{
        return render(source) to (width to height)
    }

    fun render(source:String):String{
        val diagram = source.split("\n").map { it.trimEnd() }

        var w = 0
        val h = diagram.size

        diagram.forEachIndexed{ y, line ->
            println(line)
            line.forEachIndexed { x, _ ->
                if (line.length > w) {
                    w = diagram[x].length;
                }
            }
        }
        println("w:$w,h:$h")
        width = w * 30 * zoom
        height = h * 54 * zoom

       val svg = com.gitee.wsl.common.svg.SVG.svg {
            width = (w * 30 * zoom).UT
            height = (h * 54 * zoom).UT
            attributes["debug"] = isDebug.toString()

            attributes["viewBox"] = "${-padding} ${-padding} ${w * 30 + 2 * padding} ${h * 54 + 2 * padding}"

            style {
                body = """
                 .diagram {
                  display: block;
                 }
                 
                 .diagram line, .diagram circle, .diagram rect {
                   stroke: black;
                 }
                 
                 .diagram line {
                   stroke-width: 2;
                 }
                 
                 .diagram circle {
                   r: 3.5;
                 }
                 
                 .diagram rect {
                   width: 6px;
                   height: 6px;
                 }
                 
                 .diagram text, .glyph, .debug text {
                   /** font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; **/
                   font-family: Iosevka Fixed, monospace;
                   font-size: 3em;
                   text-anchor: middle;
                   alignment-baseline: central;
                   white-space: pre;
                 }
                 
                 .reserved {
                   fill: transparent;
                   white-space: pre;
                 }
                 
                 polygon {
                   stroke-width: 0;
                 }

                 polygon {
                   stroke: black;
                   /** stroke-width: 0.2; **/
                   stroke-linecap: butt;
                   fill: black;
                 }
                 
                 line.part {
                   stroke-width: 6;
                   stroke-linecap: butt;
                   stroke: black;
                 }
                 
                """.trimIndent()

                if(isDebug)
                    body+="""
                 .debug[debug="true"] .reserved {
                   fill: black;
                   opacity: 0.5;
                 }
                 
                 .debug[debug="true"] line.grid {
                   stroke: black;
                   stroke-width: 0.2;
                   stroke-linecap: butt;
                   fill: black;
                   opacity: 1%;
                 }
                 
                 .debug[debug="true"] polygon.inner {
                   fill: black;
                   stroke: black;
                   opacity: 5%;
                 }
                 
                  .debug[debug="true"] polygon,
                 .debug[debug="true"] line.grid
                 {
                   opacity: 10%;
                 }
                 
                 .debug[debug="true"] polygon,
                 .debug[debug="true"] path,
                 .debug[debug="true"] circle
                 {
                   opacity: 50%;
                 }
                 
                 .debug[debug="true"] polygon {
                   fill: red;
                   stroke: red;
                 }
                 
                 
                 .debug[debug="true"] circle,
                 .debug[debug="true"] path
                 {
                   opacity: 50%;
                   fill: red;
                 }
                 
                 .debug[debug="true"] circle {
                   stroke: red;
                 }
                 
                 .debug[debug="true"] .inner {
                   stroke-width: 0.2;
                 }
                 
                  .debug[debug="true"] line.part {
                   opacity: 50%;
                   stroke: red;
                 }
                 
                 .debug[debug="true"] line.center {
                   stroke-width: 3;
                   stroke-linecap: butt;
                   opacity: 10%;
                   stroke: black;
                 }
                 /**
                 text::selection {
                     fill: black;
                     background-color: #EEE;
                 }
                 **/
                 
                    """.trimIndent()
            }
            parser(diagram,this)

            /*if(isDebug)
                grid(w,h,this)*/

        }

     return svg.render()

    }

    private fun around(diagram:List<String>, x:Int, y:Int):CellAround {
        val cell = CellAround()
        val hasTop = y > 0 && x < diagram[y-1].length
        val hasBottom = y < diagram.size-1 && x < diagram[y+1].length
        if (hasTop) {
            cell.top = diagram[y - 1][x]
        }
        if (x < diagram[y].length - 1) {
            cell.right = diagram[y][x + 1]
        }
        if (hasBottom ) {
            cell.bottom = diagram[y + 1][x]
        }
        if (x > 0) {
            cell.left = diagram[y][x - 1]
        }
        if (hasTop && x < (diagram[y - 1].length - 1)) {
            // console.log(`@${diagram[y][x]}: ${diagram[y - 1][x + 1]}`);
            cell.topRight = diagram[y - 1][x + 1]
        }
        //if (diagram[y][x] == ".") {
        //console.log(`${diagram[y][x]}}: ${(y + 1) < (diagram.length)}`);
        //console.log(diagram[y + 1]);
        //throw new Error("hi");
        //}
        if (hasBottom && x < diagram[y + 1].length -1 ) {
            cell.bottomRight = diagram[y + 1][x + 1]
            //console.log(diagram[y + 1]);
            //console.log(`${diagram[y][x]}: ${x} ${y} ${bottomRight}`);
            //throw new Error("hi");
        }
        if (hasBottom && x > 0) {
            cell.bottomLeft = diagram[y + 1][x - 1]
        }

        if (hasTop && x > 0) {
            cell.topLeft = diagram[y - 1][x - 1]
        }

        return cell
    }


    companion object{
       val glyphsCharList = listOf('|','─','-','~','_',':','=','*','o','/','\\','#','┐','┌','+','└','┘','.','\'','`','>','►','<','v','V','^')
       val INSTANCE:QuickParser by lazy{QuickParser()}
    }
}

data class CellAround(var left: Char = ' ',
                  var  top : Char = ' ',
                  var  right:  Char = ' ',
                  var  bottom: Char = ' ',
                  var  topRight :  Char = ' ',
                  var  bottomRight :  Char = ' ',
                  var  bottomLeft : Char = ' ',
                  var  topLeft :  Char = ' ')

